home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 198_02 / line.c < prev    next >
C/C++ Source or Header  |  1990-01-21  |  16KB  |  614 lines

  1. /*
  2.  * The functions in this file are a general set of line management utilities.
  3.  * They are the only routines that touch the text. They also touch the buffer
  4.  * and window structures, to make sure that the necessary updating gets done.
  5.  * There are routines in this file that handle the kill buffer too. It isn't
  6.  * here for any good reason.
  7.  *
  8.  * Note that this code only updates the dot and mark values in the window list.
  9.  * Since all the code acts on the current window, the buffer that we are
  10.  * editing must be being displayed, which means that "b_nwnd" is non zero,
  11.  * which means that the dot and mark values in the buffer headers are nonsense.
  12.  */
  13.  
  14. #include    <stdio.h>
  15. #include    "estruct.h"
  16. #include    "edef.h"
  17.  
  18. #define BSIZE(a)    ((a + NBLOCK - 1) & (~(NBLOCK - 1)))
  19.  
  20. extern int didldel, didlins;
  21.  
  22. /* KILL *ykbuf; */    /* ptr to current kill buffer chunk being yanked */
  23. /* int ykboff; */    /* offset into that chunk */
  24.  
  25. /*
  26.  * This routine allocates a block of memory large enough to hold a LINE
  27.  * containing "used" characters. The block is always rounded up a bit. Return
  28.  * a pointer to the new block, or NULL if there isn't any memory left. Print a
  29.  * message in the message line if no space.
  30.  */
  31. LINE *lalloc(used)
  32.  
  33. register int    used;
  34.  
  35. {
  36.     register LINE    *lp;
  37.     char *malloc();
  38.  
  39.     if ((lp = (LINE *) malloc(sizeof(LINE)+used)) == NULL) {
  40.         mlwrite("[OUT OF MEMORY]");
  41.         return (NULL);
  42.     }
  43.     lp->l_size = used;
  44.     lp->l_used = used;
  45.     return (lp);
  46. }
  47.  
  48. /*
  49.  * Delete line "lp". Fix all of the links that might point at it (they are
  50.  * moved to offset 0 of the next line. Unlink the line from whatever buffer it
  51.  * might be in. Release the memory. The buffers are updated too; the magic
  52.  * conditions described in the above comments don't hold here.
  53.  */
  54. lfree(lp)
  55. register LINE    *lp;
  56. {
  57.     register BUFFER *bp;
  58.     register WINDOW *wp;
  59.  
  60.     wp = wheadp;
  61.     while (wp != NULL) {
  62.         if (wp->w_linep == lp)
  63.             wp->w_linep = lp->l_fp;
  64.         if (wp->w_dotp    == lp) {
  65.             wp->w_dotp  = lp->l_fp;
  66.             wp->w_doto  = 0;
  67.         }
  68.         if (wp->w_markp == lp) {
  69.             wp->w_markp = lp->l_fp;
  70.             wp->w_marko = 0;
  71.         }
  72.         wp = wp->w_wndp;
  73.     }
  74.     bp = bheadp;
  75.     while (bp != NULL) {
  76.         if (bp->b_nwnd == 0) {
  77.             if (bp->b_dotp    == lp) {
  78.                 bp->b_dotp = lp->l_fp;
  79.                 bp->b_doto = 0;
  80.             }
  81.             if (bp->b_markp == lp) {
  82.                 bp->b_markp = lp->l_fp;
  83.                 bp->b_marko = 0;
  84.             }
  85.         }
  86.         bp = bp->b_bufp;
  87.     }
  88.     lp->l_bp->l_fp = lp->l_fp;
  89.     lp->l_fp->l_bp = lp->l_bp;
  90.     free((char *) lp);
  91. }
  92.  
  93. /*
  94.  * This routine gets called when a character is changed in place in the current
  95.  * buffer. It updates all of the required flags in the buffer and window
  96.  * system. The flag used is passed as an argument; if the buffer is being
  97.  * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
  98.  * mode line needs to be updated (the "*" has to be set).
  99.  */
  100. lchange(flag)
  101. register int    flag;
  102. {
  103.     register WINDOW *wp;
  104.  
  105.     if (curbp->b_nwnd != 1)         /* Ensure hard.     */
  106.         flag = WFHARD;
  107.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so    */
  108.         flag |= WFMODE;         /* update mode lines.    */
  109.         curbp->b_flag |= BFCHG;
  110.     }
  111.     wp = wheadp;
  112.     while (wp != NULL) {
  113.         if (wp->w_bufp == curbp)
  114.             wp->w_flag |= flag;
  115.         wp = wp->w_wndp;
  116.     }
  117. }
  118.  
  119. insspace(f, n)    /* insert spaces forward into text */
  120.  
  121. int f, n;    /* default flag and numeric argument */
  122.  
  123. {
  124.     linsert(n, ' ');
  125.     backchar(f, n);
  126. }
  127.  
  128. /*
  129.  * linstr -- Insert a string at the current buffer point
  130.  */
  131.  
  132. linstr(instr)
  133. char *instr;
  134. {
  135.     register int status;
  136.  
  137.     status = TRUE;
  138.     if (instr != NULL)
  139.         while (*instr && status == TRUE) {
  140.             status = ((*instr == '\n')?
  141.                 lnewline(): linsert(1, *instr));
  142.             /* Insertion error? */
  143.             if (status != TRUE) {
  144.                 mlwrite("%%Can not insert string");
  145.                 break;
  146.             }
  147.             instr++;
  148.         }
  149.     return(status);
  150. }
  151.  
  152. /*
  153.  * Insert "n" copies of the character "c" at the current location of dot. In
  154.  * the easy case all that happens is the text is stored in the line. In the
  155.  * hard case, the line has to be reallocated. When the window list is updated,
  156.  * take special care; I screwed it up once. You always update dot in the
  157.  * current window. You update mark, and a dot in another window, if it is
  158.  * greater than the place where you did the insert. Return TRUE if all is
  159.  * well, and FALSE on errors.
  160.  */
  161. linsert(n, c)
  162. {
  163.     register char    *cp1;
  164.     register char    *cp2;
  165.     register LINE    *lp1;
  166.     register LINE    *lp2;
  167.     register LINE    *lp3;
  168.     register int    doto;
  169.     register int    i;
  170.     register WINDOW *wp;
  171.  
  172.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  173.         return(rdonly());    /* we are in read only mode    */
  174.     lchange(WFEDIT);
  175.     lp1 = curwp->w_dotp;            /* Current line     */
  176.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  177.         if (curwp->w_doto != 0) {
  178.             mlwrite("bug: linsert");
  179.             return (FALSE);
  180.         }
  181.         if ((lp2=lalloc(BSIZE(n))) == NULL) /* Allocate new line*/
  182.             return (FALSE);
  183.         lp2->l_used = n;
  184.         lp3 = lp1->l_bp;        /* Previous line    */
  185.         lp3->l_fp = lp2;        /* Link in        */
  186.         lp2->l_fp = lp1;
  187.         lp1->l_bp = lp2;
  188.         lp2->l_bp = lp3;
  189.         for (i=0; i<n; ++i)
  190.             lp2->l_text[i] = c;
  191.         curwp->w_dotp = lp2;
  192.         curwp->w_doto = n;
  193.         return (TRUE);
  194.     }
  195.     doto = curwp->w_doto;            /* Save for later.    */
  196.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  197.         if ((lp2=lalloc(BSIZE(lp1->l_used+n))) == NULL)
  198.             return (FALSE);
  199.         lp2->l_used = lp1->l_used+n;
  200.         cp1 = &lp1->l_text[0];
  201.         cp2 = &lp2->l_text[0];
  202.         while (cp1 != &lp1->l_text[doto])
  203.             *cp2++ = *cp1++;
  204.         cp2 += n;
  205.         while (cp1 != &lp1->l_text[lp1->l_used])
  206.             *cp2++ = *cp1++;
  207.         lp1->l_bp->l_fp = lp2;
  208.         lp2->l_fp = lp1->l_fp;
  209.         lp1->l_fp->l_bp = lp2;
  210.         lp2->l_bp = lp1->l_bp;
  211.         free((char *) lp1);
  212.     } else {                /* Easy: in place    */
  213.         lp2 = lp1;            /* Pretend new line    */
  214.         lp2->l_used += n;
  215.         cp2 = &lp1->l_text[lp1->l_used];
  216.         cp1 = cp2-n;
  217.         while (cp1 != &lp1->l_text[doto])
  218.             *--cp2 = *--cp1;
  219.     }
  220.     for (i=0; i<n; ++i)            /* Add the characters    */
  221.         lp2->l_text[doto+i] = c;
  222.     wp = wheadp;                /* Update windows    */
  223.     while (wp != NULL) {
  224.         if (wp->w_linep == lp1)
  225.             wp->w_linep = lp2;
  226.         if (wp->w_dotp == lp1) {
  227.             wp->w_dotp = lp2;
  228.             if (wp==curwp || wp->w_doto>doto)
  229.                 wp->w_doto += n;
  230.         }
  231.         if (wp->w_markp == lp1) {
  232.             wp->w_markp = lp2;
  233.             if (wp->w_marko > doto)
  234.                 wp->w_marko += n;
  235.         }
  236.         wp = wp->w_wndp;
  237.     }
  238.     return (TRUE);
  239. }
  240.  
  241. /*
  242.  * Insert a newline into the buffer at the current location of dot in the
  243.  * current window. The funny ass-backwards way it does things is not a botch;
  244.  * it just makes the last line in the file not a special case. Return TRUE if
  245.  * everything works out and FALSE on error (memory allocation failure). The
  246.  * update of dot and mark is a bit easier then in the above case, because the
  247.  * split forces more updating.
  248.  */
  249. lnewline()
  250. {
  251.     register char    *cp1;
  252.     register char    *cp2;
  253.     register LINE    *lp1;
  254.     register LINE    *lp2;
  255.     register int    doto;
  256.     register WINDOW *wp;
  257.  
  258.     if (curbp->b_mode&MDVIEW)    /* don't allow this command if    */
  259.         return(rdonly());    /* we are in read only mode    */
  260.     lchange(WFHARD);
  261.     ++didlins;
  262.     lp1  = curwp->w_dotp;            /* Get the address and    */
  263.     doto = curwp->w_doto;            /* offset of "."    */
  264.     if ((lp2=lalloc(doto)) == NULL)     /* New first half line    */
  265.         return (FALSE);
  266.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  267.     cp2 = &lp2->l_text[0];
  268.     while (cp1 != &lp1->l_text[doto])
  269.         *cp2++ = *cp1++;
  270.     cp2 = &lp1->l_text[0];
  271.     while (cp1 != &lp1->l_text[lp1->l_used])
  272.         *cp2++ = *cp1++;
  273.     lp1->l_used -= doto;
  274.     lp2->l_bp = lp1->l_bp;
  275.     lp1->l_bp = lp2;
  276.     lp2->l_bp->l_fp = lp2;
  277.     lp2->l_fp = lp1;
  278.     wp = wheadp;                /* Windows        */
  279.     while (wp != NULL) {
  280.         if (wp->w_linep == lp1)
  281.             wp->w_linep = lp2;
  282.         if (wp->w_dotp == lp1) {
  283.             if (wp->w_doto < doto)
  284.                 wp->w_dotp = lp2;
  285.             else
  286.                 wp->w_doto -= doto;
  287.         }
  288.         if (wp->w_markp == lp1) {
  289.             if (wp->w_marko < doto)
  290.                 wp->w_markp = lp2;
  291.             else
  292.                 wp->w_marko -= doto;
  293.         }
  294.         wp = wp->w_wndp;
  295.     }
  296.     return (TRUE);
  297. }
  298.  
  299. /*
  300.  * This function deletes "n" bytes, starting at dot. It understands how do deal
  301.  * with end of lines, etc. It returns TRUE if all of the characters were
  302.  * delet